#include <vector>
#include <sstream>
#include <fstream>
#include <cmath>
#include "LCSAlgorithm.h"

unsigned int LCSAlgorithm::LCS(const std::string& s1, const std::string& s2) const {
    size_t n = s1.length();
    size_t m = s2.length();
    std::vector<std::vector<unsigned int>> c(2, std::vector<unsigned int>(m + 1, 0));
    
    for (size_t i = 0; i < n; ++i) {
        for (size_t j = 0; j < m; ++j) {
            if (s1[i] ^ s2[j]) {
                c[1][j + 1] = std::max(c[1][j], c[0][j + 1]);
            } else {
                c[1][j + 1] = c[0][j] + 1;
            }
        }
        c[0].swap(c[1]);
    }

    return c[0][m];
}
 
double LCSAlgorithm::getSim(const FilePairType& file_pair) const {

    auto first_filename = file_pair.first->filename;
    auto second_filename = file_pair.second->filename;
    std::ifstream first_stream(first_filename.data(), std::ifstream::in);
    std::stringstream first_buffer;
    first_buffer << first_stream.rdbuf();
    
    std::ifstream second_stream(second_filename.data(), std::ifstream::in);
    std::stringstream second_buffer;
    second_buffer << second_stream.rdbuf();
    
    const std::string& first_string = first_buffer.str();
    const std::string& second_string = second_buffer.str();
    size_t n = first_string.length();
    size_t m = second_string.length();

    if (!n && !m) {
        return 1.0;
    }

    auto numerator = LCS(first_string, second_string);
    double denominator = sqrt((n * n + m * m) / 2.0);

    return numerator / denominator;
}
